﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Syntezator_mowy.Extras.Exception;

namespace Merger.Wav
{
    class WavDataSChunk
    {
        private byte[] chunkId;
        private byte[] chunkSize;
        private byte[] data;

        private string sourcePath;

        public int DataLength
        {
            get
            {
                if (this.chunkSize != null)
                    return BitConverter.ToInt32(this.chunkSize, 0);
                else
                    throw new DataSubChunkFormatException();
            }
            set
            {
                if (value.GetType() == typeof(int))
                {         
                    this.chunkSize = BitConverter.GetBytes(value);
                }
            }
        }

        public static int dataLength(byte[] chunkSize)
        {
            return BitConverter.ToInt32(chunkSize, 0);
        }

        public WavDataSChunk(string sourcePath) : this(0, sourcePath) { }

        public WavDataSChunk(int chunkSize,string sourcePath)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            this.chunkId = new byte[4];
            this.chunkId = encoder.GetBytes("data");
            this.chunkSize = new byte[4];
            this.chunkSize = BitConverter.GetBytes(chunkSize);
            this.data = null;

            this.sourcePath = sourcePath;
        }

        public WavDataSChunk(byte[] chunkId, byte[] chunkSize, string sourcePath)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            if (chunkId.Length != 4)
                throw new WrongFormatException();
            else if (encoder.GetString(chunkId) != "data")
                throw new DataSubChunkFormatException();
            else
                this.chunkId = chunkId;
            if (chunkSize.Length != 4)
                throw new WrongFormatException();
            else
                this.chunkSize = chunkSize;

            this.data = null;
            this.sourcePath = sourcePath;
        }

        public WavDataSChunk(byte[] chunkId, byte[] chunkSize, byte[] data)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            if (chunkId.Length != 4)
                throw new WrongFormatException();
            else if (encoder.GetString(chunkId) != "data")
                throw new DataSubChunkFormatException();
            else
                this.chunkId = chunkId;
            if (chunkSize.Length != 4)
                throw new WrongFormatException();
            else
                this.chunkSize = chunkSize;

            this.data = data;
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            WavDataSChunk chunk = obj as WavDataSChunk;
            if (chunk == null)
                return false;

            return ((this.chunkSize == chunk.chunkSize) && (this.data == chunk.data));
        }

        public bool Equals(WavDataSChunk chunk)
        {
            if (chunk == null)
                return false;

            return ((this.chunkSize == chunk.chunkSize) && (this.data == chunk.data));
        }

        public override int GetHashCode()
        {
            return this.chunkId.GetHashCode() ^ this.chunkSize.GetHashCode() ^ this.data.GetHashCode();
        }

        public static bool operator==(WavDataSChunk a, WavDataSChunk b)
        {
            if (Object.ReferenceEquals(a, b))
                return true;
            if ((a == null) || (b == null))
                return false;

            return ((a.chunkSize == b.chunkSize) && (a.data == b.data));
        }

        public static bool operator!=(WavDataSChunk a, WavDataSChunk b)
        {
            return !(a==b);
        }

        public void saveDataChunk(string destinationPath)
        {
            using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(destinationPath)))
            {
                writer.Seek(0, SeekOrigin.End);

                writer.Write(this.chunkId);
                writer.Write(this.chunkSize);

                if (this.data == null) this.appendData(destinationPath);
                else writer.Write(this.data);
            }
        }

        public void changeSubChunkSize(string destinationPath, int value)
        {
            using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(destinationPath)))
            {
                writer.Seek(42, SeekOrigin.Begin);
                writer.Write(BitConverter.GetBytes(value));
                this.chunkSize = BitConverter.GetBytes(value);
            }
        }

        public void appendData(string destinationPath)
        {
            using (BinaryReader reader = new BinaryReader(File.OpenRead(this.sourcePath)))
            {
                using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(destinationPath)))
                {
                    reader.BaseStream.Seek(46, SeekOrigin.Begin);
                    writer.Seek(0, SeekOrigin.End);
                    int pos = 46;
                    int len = (int)reader.BaseStream.Length;
                    const int bufferSize = 200;

                    while (pos < len)
                    {
                        byte[] buffer = utworzBuforNaDane(pos, len, bufferSize);

                        pos += reader.Read(buffer, 0, buffer.Length);
                        writer.Write(buffer);
                    }
                }
            }
        }

        private static byte[] utworzBuforNaDane(int pos, int len, int bufferSize)
        {
            int iloscZnakow;
            if (pos + bufferSize < len) iloscZnakow = bufferSize;
            else iloscZnakow = len - pos;
            byte[] buffer = new byte[iloscZnakow];
            return buffer;
        }
    }
}
